package com.iteaj.iot.test.modbus.dtu;

import com.iteaj.iot.FrameworkManager;
import com.iteaj.iot.ProtocolType;
import com.iteaj.iot.client.IotClient;
import com.iteaj.iot.client.TcpSocketClient;
import com.iteaj.iot.client.protocol.ServerInitiativeProtocol;
import com.iteaj.iot.consts.ExecStatus;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientCommonProtocol;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientMessage;
import com.iteaj.iot.modbus.consts.ModbusCode;
import com.iteaj.iot.modbus.server.tcp.ModbusTcpBody;
import com.iteaj.iot.modbus.server.tcp.ModbusTcpHeader;
import com.iteaj.iot.test.TestProtocolType;
import com.iteaj.iot.utils.ByteUtil;
import io.netty.buffer.Unpooled;

import java.util.concurrent.TimeUnit;

/**
 * 模拟服务端使用Modbus Tcp协议请求Dtu设备
 */
public class ModbusTcpForDtuClientTestProtocol extends ServerInitiativeProtocol<ModbusTcpForDtuClientTestMessage> {

    private ModbusTcpClientMessage message;

    public ModbusTcpForDtuClientTestProtocol(ModbusTcpForDtuClientTestMessage requestMessage) {
        super(requestMessage);
    }

    @Override
    protected void doBuildRequestMessage(ModbusTcpForDtuClientTestMessage requestMessage) {
        ModbusTcpBody body = ModbusTcpBody.copy(requestMessage().getBody());
        ModbusTcpHeader header = ModbusTcpHeader.copy(requestMessage().getHead());

        ModbusTcpClientCommonProtocol commonProtocol = ModbusTcpClientCommonProtocol.build(header, body);
        // 可能会提示死锁问题, 这里由于需要同步测试所以有一定的概率导致死锁 并没有逻辑问题
        commonProtocol.sync(2000).request(protocol -> {
            if(protocol.getExecStatus() == ExecStatus.success) {
                ModbusCode code = body.getCode();
                if(code == ModbusCode.Read03) {
                    IotClient client = FrameworkManager.getClient(requestMessage.getClass());
                    // 做拆包测试
                    if(client instanceof TcpSocketClient) {
                        ModbusTcpForDtuClientTestMessage clientTestMessage = this.buildResponseMessage(commonProtocol.responseMessage());
                        clientTestMessage.writeBuild();
                        byte[] message = clientTestMessage.getMessage();
                        if(message.length > 128) { // 拆成三包
                            byte[] bytes = ByteUtil.subBytes(message, 0, 30);
                            ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(bytes));
                            try {
                                TimeUnit.MILLISECONDS.sleep(70); // 休眠100毫秒
                                bytes = ByteUtil.subBytes(message, 30, 60);
                                ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(bytes));

                                TimeUnit.MILLISECONDS.sleep(50); // 休眠100毫秒
                                bytes = ByteUtil.subBytes(message, 60);
                                ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(bytes));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(message));
                        }
                    }
                } else {
                    this.message = commonProtocol.responseMessage();
                }
            } else {
                logger.error("modbus over失败");
            }
            return null;
        });

    }

    @Override
    protected ModbusTcpForDtuClientTestMessage doBuildResponseMessage() {
        if(this.message != null) {
            return this.buildResponseMessage(this.message);
        } else {
            return null;
        }
    }

    protected ModbusTcpForDtuClientTestMessage buildResponseMessage(ModbusTcpClientMessage tcpClientMessage) {
        // 恢复NextId
        ModbusTcpHeader head = requestMessage().getHead();
        tcpClientMessage.getHead().setNextId(head.getNextId());
        tcpClientMessage.getHead().buildNextId(head.getNextId());
        return new ModbusTcpForDtuClientTestMessage(tcpClientMessage.getHead(), tcpClientMessage.getBody());
    }

    @Override
    public ProtocolType protocolType() {
        return TestProtocolType.PIReq;
    }
}
